package com.zp.resource.user;

import java.util.ArrayList;import java.util.Date;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.stereotype.Component;

import com.sun.jersey.spi.resource.Singleton;
import com.zp.bean.common.ResultCommonVo;
import com.zp.bean.user.ResultLoginVo;
import com.zp.bean.user.ResultRoleVo;
import com.zp.bean.user.ResultUserVo;
import com.zp.bean.user.UserVo;
import com.zp.domain.LoginInfo;
import com.zp.domain.Role;
import com.zp.domain.User;
import com.zp.domain.UserRole;
import com.zp.resource.common.BaseServices;
import com.zp.util.Constant;
import com.zp.util.MD5Util;
import com.zp.util.MyException;

/**
 * user services
 * 
 * @author chenlijun08@gmail.com
 * 
 * @version 1.0
 * 
 * @date 2014/2/15
 * 
 */

@Component
@Path("rest/user")
@Singleton
public class UserServices extends BaseServices {

	/**
	 * login web system path:/user/login Http:POST
	 * 
	 * @param loginName
	 * 
	 * @param loginPass
	 * 
	 * @param sysName
	 * 
	 * @return Response,ResultUserVo with JSON String
	 *         like:{"code":268,"message":"OK","totalCount":1,"login":{"id":
	 *         "402881e64459ad0e014459adc3b00001"
	 *         ,"username":"Alex","password":"b3275960d68fda9d831facc0426c3bbc"
	 *         ,"status"
	 *         :"1","passErrorCount":0,"passStatus":"1","passUpdateTime"
	 *         :null},"key":"8ea96781b7315eb13aaca08e4ffc71ee"}
	 */
	@POST
	@Path("/login")
	@Produces(MediaType.APPLICATION_JSON)
	public Response login(@QueryParam("loginName") String loginName,
			@QueryParam("loginPass") String loginPass,
			@QueryParam("sysName") String sysName) {
		logger.info("login called loginName is:" + loginName + " sysName:"
				+ sysName);
		ResultLoginVo result = new ResultLoginVo();
		String jpql = "from LoginInfo where username=? and password=? and status=?";
		Object[] queryParams = { loginName, loginPass, "1" };
		List<?> list;
		try {
			list = this.jpaDao.getResultData(Constant.NEGATIVE_ONE,
					Constant.NEGATIVE_ONE, jpql, queryParams);
			if (list != null && list.size() > Constant.ZERO) {
				LoginInfo login = (LoginInfo) list.get(Constant.ZERO);
				result.setLogin(login);
				result.setCode(Constant.SUCCESS_CODE);
				result.setMessage(Constant.OK);
				long expiryTime = System.currentTimeMillis();
				expiryTime += 1000L * Constant.EIGHT_HOUR_S;
				String signatureValue = makeTokenSignature(expiryTime,
						loginName, loginPass, sysName);
				result.setKey(signatureValue);
			} else {
				result.setCode(Constant.SUCCESS_CODE);
				result.setMessage(Constant.USER_NOT_EXITS);
			}
		} catch (MyException e) {
			result.setCode(Constant.FAILE_CODE);
			result.setMessage(e.getMessage());
			e.printStackTrace();
		}

		return Response.ok(result).build();
	}

	/**
	 * login out web system
	 * 
	 * @return Response
	 */
	@GET
	@Path("/loginout")
	@Produces(MediaType.APPLICATION_JSON)
	public Response loginOut() {
		// login.setstatus(Constant.OFF);
		return Response.ok(Constant.OK).build();
	}

	/**
	 * update user password path:/user/updatePass Http:POST
	 * 
	 * @param updatePass
	 *            like{"userId":"1234567","orginalPassword":"123456":
	 *            "newPassword":"1234567"}
	 * 
	 * @return Response,ResultCommonVo with JSON
	 *         String,{"code":268,"message":"OK","totalCount":1}
	 */
	@POST
	@Path("/updatePass")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response updateUserPassword(
			@QueryParam("updatePass") String updatePass) {
		logger.info("updateUserPassword called updatePass is:" + updatePass);
		ResultCommonVo result = new ResultCommonVo();
		try {
			JSONObject record = this.getJSONObject(updatePass);
			String userId = record.getString("userId");
			String orginalPassword = record.getString("orginalPassword");
			String newPassword = record.getString("newPassword");
			if (orginalPassword.equals(newPassword)) {
				result.setCode(Constant.FAILE_CODE);
				result.setMessage(Constant.PASS_SAME);
			} else {
				try {
					LoginInfo login = (LoginInfo) this.jpaDao.findById(
							LoginInfo.class, userId);
					if(login!=null){
					if (login.getPassword().equals(orginalPassword)) {
						login.setPassword(newPassword);
						this.jpaDao.update(login);
						result.setCode(Constant.SUCCESS_CODE);
						result.setMessage(Constant.OK);
					}
					}
				} catch (MyException e) {
					result.setCode(Constant.FAILE_CODE);
					result.setMessage(e.getMessage());
					e.printStackTrace();
				}
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}

		return Response.ok(result).build();
	}

	/**
	 * register user information path:/user/registerUser Http:POST
	 * 
	 * @param jsonContext
	 *            JSON string like:{"username":"Alex","password":
	 *            "b3275960d68fda9d831facc0426c3bbc"}
	 * @return Response,ResultCommonVo with JSON String
	 *         like:{"code":268,"message":"OK","totalCount":1}
	 */
	@POST
	@Path("/registerUser")
	@Produces(MediaType.APPLICATION_JSON)
	public Response registerUser(@QueryParam("jsonContext") String jsonContext) {
		logger.info("param:"+jsonContext);
		ResultCommonVo result = new ResultCommonVo();
		try{
		JSONObject record = this.getJSONObject(jsonContext);
		
		String username = record.getString("username");
		String password = record.getString("password");
		LoginInfo loginInfo = this.getLoginInfoByName(username);
		if (loginInfo == null) {
			LoginInfo login = new LoginInfo();
			login.setUsername(username);
			login.setStatus(Constant.ON);
			login.setPassword(password);
			login.setPassStatus(Constant.ON);
			try {
				this.jpaDao.save(login);
				loginInfo = this.getLoginInfoByName(username);
				User user = new User();
				user.setId(loginInfo.getId());
				user.setName(login.getUsername());
				user.setRegisterTime(new Date());
				user.setUpdateTime(new Date());
				this.jpaDao.save(user);
				UserRole userRole = new UserRole();
				userRole.setUserId(loginInfo.getId());
				Role role = this.getRoleByCode(Constant.USER_ROLE);
				userRole.setRoleId(role.getId());
				userRole.setCode(role.getCode());
				this.jpaDao.save(userRole);
				result.setCode(Constant.SUCCESS_CODE);
				result.setMessage(Constant.OK);
			} catch (MyException e) {
				result.setCode(Constant.FAILE_CODE);
				result.setMessage(e.getMessage());
				e.printStackTrace();
			}

		} else {
			result.setCode(Constant.FAILE_CODE);
			result.setMessage(Constant.USER_EXIST);
		}
	
		}catch(Exception e){
			e.printStackTrace();
			result.setCode(Constant.FAILE_CODE);
			result.setMessage(e.getMessage());
		}
		
		
			
		return Response.ok(result).build();
	}

	/**
	 * get User information with user id path:/user/getUser Http:POST
	 * 
	 * @param userId
	 * 
	 * @return Response, ResultUserVo with JSON String
	 *         like:{"code":268,"message":"OK","totalCount":1,"userInfo":{"id":
	 *         "402881e64459ad0e014459adc3b00001"
	 *         ,"name":"Alex","birthday":null,"gender"
	 *         :null,"certNumber":null,"type"
	 *         :null,"registerTime":1393073964292,"updateTime"
	 *         :null,"login":{"id"
	 *         :"402881e64459ad0e014459adc3b00001","username":
	 *         "Alex","password":"e10adc3949ba59abbe56e057f20f883e"
	 *         ,"status":"1",
	 *         "passErrorCount":0,"passStatus":"1","passUpdateTime"
	 *         :null}},"listVo":null}
	 */
	@POST
	@Path("/getUser")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getUserById(@QueryParam("userId") String userId) {
		logger.info("getUserById called userId:" + userId);
		ResultUserVo result = new ResultUserVo();
		LoginInfo login;
		result.setCode(Constant.SUCCESS_CODE);
		result.setMessage(Constant.OK);
		try {
			login = (LoginInfo) this.jpaDao.findById(LoginInfo.class, userId);
			if (login != null) {
				UserVo vo = new UserVo();
				User user = (User) this.jpaDao.findById(User.class, userId);
				vo.setBirthday(user.getBirthday());
				vo.setCertNumber(user.getCertNumber());
				vo.setGender(user.getGender());
				vo.setId(user.getId());
				vo.setLogin(login);
				vo.setName(user.getName());
				vo.setRegisterTime(user.getRegisterTime());
				vo.setType(this.getTypeByCode(user.getTypeCode()));
				vo.setUpdateTime(user.getUpdateTime());
				result.setUserInfo(vo);
			}
		} catch (MyException e) {
			result.setCode(Constant.FAILE_CODE);
			result.setMessage(e.getMessage());
			e.printStackTrace();
		}

		return Response.ok(result).build();
	}

	/**
	 * get user by user name or login name or type code Path:/user/getUsers
	 * Http:POST
	 * 
	 * @param pageNo
	 * 
	 * @param pageSize
	 * 
	 * @param content
	 *            user name or login name or type code if ignored the value is
	 *            null
	 * 
	 * @return Response,ResultUserVo with JSON String
	 *         like:{"code":268,"message":
	 *         "OK","totalCount":1,"userInfo":null,"listVo"
	 *         :[{"id":"402881e64459ad0e014459adc3b00001"
	 *         ,"name":"Alex","birthday"
	 *         :null,"gender":null,"certNumber":null,"type"
	 *         :null,"registerTime":1393073964000
	 *         ,"updateTime":null,"login":{"id"
	 *         :"402881e64459ad0e014459adc3b00001"
	 *         ,"username":"Alex","password":"b3275960d68fda9d831facc0426c3bbc"
	 *         ,"status"
	 *         :"1","passErrorCount":0,"passStatus":"1","passUpdateTime"
	 *         :null}}]}
	 */
	@POST
	@Path("/getUsers")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getUsersByCriteria(@QueryParam("pageNo") int pageNo,
			@QueryParam("pageSize") int pageSize,
			@QueryParam("content") String content) {
		logger.info("getUsersByCriteria called json pageNo:" + pageNo
				+ " pageSize:" + pageSize + " content:" + content);
		String jpql = "from User u,LoginInfo l where u.id=l.id and (u.name=? or u.typeCode=? or l.username=?) order by l.username asc";
		List<?> list = null;
		ResultUserVo result = new ResultUserVo();
		List<UserVo> lt = new ArrayList<UserVo>();
		result.setCode(Constant.SUCCESS_CODE);
		result.setMessage(Constant.OK);
		if ("".equals(content) || content == null) {
			jpql = "from User u,LoginInfo l where u.id=l.id order by l.username asc";
			try {
				list = this.jpaDao.getResultData(pageNo, pageSize, jpql, null);
				long totalCount = this.jpaDao
						.getCount(
								"select count(u.id) from User u,LoginInfo l where u.id=l.id",
								null);
				result.setTotalCount(totalCount);
			} catch (MyException e) {
				result.setCode(Constant.FAILE_CODE);
				result.setMessage(e.getMessage());
				e.printStackTrace();
			}
		} else {
			Object[] param = { content, content, content };
			try {
				list = this.jpaDao.getResultData(pageNo, pageSize, jpql, param);
				long totalCount = this.jpaDao
						.getCount(
								"select count(u.id) from User u,LoginInfo l where u.id=l.id and (u.name=? or u.typeCode=? or l.username=?)",
								param);
				result.setTotalCount(totalCount);
			} catch (MyException e) {
				result.setCode(Constant.FAILE_CODE);
				result.setMessage(e.getMessage());
				e.printStackTrace();
			}
		}
		if (list != null && list.size() > Constant.ZERO) {
			for (Object o : list) {
				Object[] data = (Object[]) o;
				User user = (User) data[Constant.ZERO];
				LoginInfo login = (LoginInfo) data[Constant.ONE];
				UserVo vo = new UserVo();
				vo.setBirthday(user.getBirthday());
				vo.setCertNumber(user.getCertNumber());
				vo.setGender(user.getGender());
				vo.setId(user.getId());
				vo.setLogin(login);
				vo.setName(user.getName());
				vo.setRegisterTime(user.getRegisterTime());
				vo.setType(this.getTypeByCode(user.getTypeCode()));
				vo.setUpdateTime(user.getUpdateTime());
				lt.add(vo);
			}
			result.setListVo(lt);

		}
		return Response.ok(result).build();
	}

	/**
	 * update user information path:/user/updateUser Http:PUT
	 * 
	 * @param user
	 * 
	 * 
	 * @return Response, ResultCommonVo with JSON
	 *         String,like:{"code":268,"message":"OK","totalCount":1}
	 */
	@PUT
	@Path("/updateLoginInfo")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response updateUser(User user) {
		ResultCommonVo result = new ResultCommonVo();
		try {
			this.jpaDao.update(user);
			result.setCode(Constant.SUCCESS_CODE);
			result.setMessage(Constant.OK);
		} catch (MyException e) {
			result.setCode(Constant.FAILE_CODE);
			result.setMessage(e.getMessage());
			e.printStackTrace();
		}

		return Response.ok(result).build();
	}

	/**
	 * used for start user,stop user,rest password,unlock function both them are
	 * update login information path:/user/updateLogin Http:PUT
	 * 
	 * @param loginInfo
	 * 
	 * @return Response, ResultCommonVo with JSON String
	 *         like:{"code":268,"message":"OK","totalCount":1}
	 */
	@PUT
	@Path("/updateLogin")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response controlUser(LoginInfo loginInfo) {
		ResultCommonVo result = new ResultCommonVo();
		try {
			this.jpaDao.update(loginInfo);
			result.setCode(Constant.SUCCESS_CODE);
			result.setMessage(Constant.OK);
		} catch (MyException e) {
			result.setCode(Constant.FAILE_CODE);
			result.setMessage(e.getMessage());
			e.printStackTrace();
		}
		return Response.ok(result).build();

	}

	/**
	 * assign one role to user path:/user/assignRole Http:POST
	 * 
	 * @param userRole
	 * 
	 * @return Response,ResultCommonVo with JSON String
	 *         like:{"code":268,"message":"OK","totalCount":1}
	 */
	@POST
	@Path("/assignRole")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response assignRoleToUser(UserRole userRole) {
		ResultCommonVo result = new ResultCommonVo();
		try {
			this.jpaDao.save(userRole);
			result.setCode(Constant.SUCCESS_CODE);
			result.setMessage(Constant.OK);
		} catch (MyException e) {
			result.setCode(Constant.FAILE_CODE);
			result.setMessage(e.getMessage());
			e.printStackTrace();
		}
		return Response.ok(result).build();

	}

	/**
	 * get user Role with user id path:/user/getUserRole Http:POST
	 * 
	 * @param userId
	 * 
	 * @return Response,ResultRoleVo with JSON String
	 *         like:{"code":268,"message":
	 *         "OK","totalCount":1,"role":null,"list":
	 *         [{"id":"402881e64458d2bb014458f050e50012"
	 *         ,"name":"普通用户","code":"G00001","status":"1"}]}
	 */
	@POST
	@Path("/getUserRole")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getUserRole(@QueryParam("userId") String userId) {
		ResultRoleVo result = new ResultRoleVo();
		List<Role> lt = new ArrayList<Role>();
		String jpql = "from UserRole where userId=? order by code asc";
		Object[] queryParams = { userId };
		result.setCode(Constant.SUCCESS_CODE);
		result.setMessage(Constant.OK);
		try {
			List<?> list = this.jpaDao.getResultData(Constant.NEGATIVE_ONE,
					Constant.NEGATIVE_ONE, jpql, queryParams);
			if (list != null && list.size() > Constant.ZERO) {
				for (Object o : list) {
					UserRole userRole = (UserRole) o;
					Role role = (Role) this.jpaDao.findById(Role.class,
							userRole.getRoleId());
					lt.add(role);
				}
				result.setList(lt);
				result.setTotalCount(list.size());
			}
		} catch (MyException e) {
			result.setCode(Constant.FAILE_CODE);
			result.setMessage(e.getMessage());
			e.printStackTrace();
		}
		return Response.ok(result).build();
	}

	/**
	 * get login information by login name
	 * 
	 * @param loginName
	 * 
	 * @return LoginInfo
	 */
	private LoginInfo getLoginInfoByName(String loginName) {
		LoginInfo login = null;
		try {
			Object[] params = { loginName };
			List<?> list = this.jpaDao.getResultData(Constant.NEGATIVE_ONE,
					Constant.NEGATIVE_ONE, "from LoginInfo where username=?",
					params);
			if (list != null & list.size() > Constant.ZERO) {
				login = (LoginInfo) list.get(Constant.ZERO);
			}
		} catch (MyException e) {
			e.printStackTrace();
		}
		return login;

	}

	private String makeTokenSignature(long tokenExpiryTime, String username,
			String password, String role) {
		String data = username + ":" + tokenExpiryTime + ":" + password + ":"
				+ role + ":" + "getKey";
		return MD5Util.MD5password(data);
	}

	private Role getRoleByCode(String code) {
		Role role = null;
		try {
			Object[] params = { code };
			List<?> list = this.jpaDao.getResultData(Constant.NEGATIVE_ONE,
					Constant.NEGATIVE_ONE, "from Role where code=?", params);
			if (list != null & list.size() > Constant.ZERO) {
				role = (Role) list.get(Constant.ZERO);
			}
		} catch (MyException e) {
			e.printStackTrace();
		}
		return role;
	}
}
